9. Verifying Revoked Credentials
In order to make sure a credential is not revoked, when making a proof request, it is important to include the
non_revoked
field. This field defines a time frame where a verifier wants a credential to be valid i.e. not revoked.
To define this time frame, the non_revoked
field has two subfields from
(optional) and to
, both accepting dates in
seconds since the Unix epoch. In most cases, the current time should be used, as the verifier is typically interested in
credentials that are valid at the time of sending the proof request. Unless, of course, the verifier's use case requires
some specific time.
NB: The
non-revoked
field can be passed as an empty object ("non-revoked":{}
), then the application will use the current time when sending the proof request.
The non-revoked
field can be specified for all requested attributes (global):
...
"indy_proof_request": {
"non_revoked": {
"from": 0,
"to": 1714727880
},
"requested_attributes": {
...
or it can be added to specific attributes individually:
...
"indy_proof_request": {
"requested_attributes": {
"surname": { "name": "Surname", "non_revoked":{"to":1714727880}},
...
When both are specified simultaneously, the attribute-specific one will take priority:
...
"indy_proof_request": {
"non_revoked":{"to":1714727999},
"requested_attributes": {
"surname": { "name": "Surname", "non_revoked":{"to":1714727880}},
"name": {"name": "Name"}
...
In the above snippet,
Surname
will be checked against the"non_revoked": {"to": 1714727880}
value, whileName
will be checked against the global value"non_revoked": {"to": 1714727999}
.
Verifying non-revoked before the revocation date
When specifying a non_revoked
time frame that precedes the revocation time, the proof request will pass. This is by
design as the credential was valid in that time frame.
Let's demonstrate:
Listing the holder's credentials:
GET /wallet/credentials
Response:
{
"results": [
{
"attrs": {
"Surname": "Alice",
"Age": "25",
"Name": "Holder"
},
"cred_def_id": "BzDvB7StHDD1HQKczybHWC:3:CL:16:Demo_Person",
"cred_rev_id": "1",
"referent": "47b18eb8-35f1-4d89-865e-d8355bec77fe",
"rev_reg_id": "BzDvB7StHDD1HQKczybHWC:4:BzDvB7StHDD1HQKczybHWC:3:CL:16:Demo_Person:CL_ACCUM:73890f4d-42fd-42c5-9a2e-b39fe0358fc6",
"schema_id": "Pp7wcmoHgeMb3td99E5Yo8:2:Person:0.1.0"
}
]
}
The holder can check the revocation status of their credential:
GET /wallet/credentials/47b18eb8-35f1-4d89-865e-d8355bec77fe/revocation-status
Response:
{
"revoked": true
}
The holder can see that their credential is revoked. Let's try a verification flow with this credential.
In this example, the verifier sends a request specifying a date/time (2024-05-07 9:00 AM) before the revocation:
POST /verifier/send-request
Request body:
{
"protocol_version": "v2",
"comment": "string",
"trace": true,
"type": "indy",
"indy_proof_request": {
"non_revoked": {
"from": 0,
"to": 1715065200
},
"requested_attributes": {
"surname": { "name": "Surname" },
"name": { "name": "Name" },
"age": { "name": "Age" }
},
"requested_predicates": {}
},
"save_exchange_record": true,
"connection_id": "cf45f341-57ad-42bc-b727-6f35e311e7e7"
}
The holder responds:
POST /verifier/accept-request
Request body:
{
"proof_id": "v2-142c6cd8-a84c-441f-b099-2b39ed6d2099",
"type": "indy",
"indy_presentation_spec": {
"requested_attributes": {
"age": {
"cred_id": "47b18eb8-35f1-4d89-865e-d8355bec77fe",
"revealed": true
},
"name": {
"cred_id": "47b18eb8-35f1-4d89-865e-d8355bec77fe",
"revealed": true
},
"surname": {
"cred_id": "47b18eb8-35f1-4d89-865e-d8355bec77fe",
"revealed": true
}
},
"requested_predicates": {},
"self_attested_attributes": {}
},
"save_exchange_record": true
}
The verifier will receive the following webhook on the proofs
topic:
{
"wallet_id": "9a7adafe-3a09-499b-a171-6d39a426bf9e",
"topic": "proofs",
"origin": "tenant faber",
"group_id": "GroupA",
"payload": {
"connection_id": "cf45f341-57ad-42bc-b727-6f35e311e7e7",
"created_at": "2024-05-07T07:21:58.776430Z",
"error_msg": null,
"parent_thread_id": null,
"presentation": null,
"presentation_request": null,
"proof_id": "v2-635d106c-7777-4368-bc57-d24f7f878343",
"protocol_version": "v2",
"role": "verifier",
"state": "done",
"thread_id": "b8c70d2b-fe36-4216-9d0a-7c30a6fceb5e",
"updated_at": "2024-05-07T07:29:10.445048Z",
"verified": true
}
}
As you can see, the holder's credential is valid ("verified": true
), since the verifier requested a
non_revoked
timestamp before the revocation took place.
Verifying non-revoked after revocation date
Now, the verifier specifies a date/time (2024-05-07 9:11 AM) after the revocation occurred
POST /verifier/send-request
Request body:
{
"protocol_version": "v2",
"comment": "string",
"trace": true,
"type": "indy",
"indy_proof_request": {
"non_revoked": {
"from": 0,
"to": 1715065860
},
"requested_attributes": {
"surname": { "name": "Surname" },
"name": { "name": "Name" },
"age": { "name": "Age" }
},
"requested_predicates": {}
},
"save_exchange_record": true,
"connection_id": "cf45f341-57ad-42bc-b727-6f35e311e7e7"
}
The holder responds:
POST /verifier/accept-request
Request body:
{
"proof_id": "v2-1894498a-579b-4dd9-9875-856c7f3f4381",
"type": "indy",
"indy_presentation_spec": {
"requested_attributes": {
"age": {
"cred_id": "47b18eb8-35f1-4d89-865e-d8355bec77fe",
"revealed": true
},
"name": {
"cred_id": "47b18eb8-35f1-4d89-865e-d8355bec77fe",
"revealed": true
},
"surname": {
"cred_id": "47b18eb8-35f1-4d89-865e-d8355bec77fe",
"revealed": true
}
},
"requested_predicates": {},
"self_attested_attributes": {}
},
"save_exchange_record": true
}
The verifier will receive the following webhook:
{
"wallet_id": "9a7adafe-3a09-499b-a171-6d39a426bf9e",
"topic": "proofs",
"origin": "tenant faber",
"group_id": "GroupA",
"payload": {
"connection_id": "cf45f341-57ad-42bc-b727-6f35e311e7e7",
"created_at": "2024-05-07T08:02:41.229378Z",
"error_msg": null,
"parent_thread_id": null,
"presentation": null,
"presentation_request": null,
"proof_id": "v2-6aaf1b87-45aa-49ee-8e2e-24fe79663fa6",
"protocol_version": "v2",
"role": "verifier",
"state": "done",
"thread_id": "53fe75f8-f4b8-4e22-ae1a-b3a13f2f41c9",
"updated_at": "2024-05-07T08:18:33.060039Z",
"verified": false
}
}
As you can see, the verification has now failed ("verified": false
).
Congratulations! You now know how to verify if credentials are revoked or not. 🥳🎉